package model

import (
	"gowork/appointmentConsultation/utils"
	"sync"
	"time"
)

type BookingTime struct {
	Id int64 `xorm:"pk autoincr"`
	ConsultantId int64
	AppointmentDate string
	Period string
	Reserved int  // 1 未被预约   2 被预约
	CreatedAt time.Time
	UpdatedAt time.Time
}

type AppointmentRecord struct {
	Id int64 `xorm:"pk autoincr"`
	OrderId int64
	ConsultantId int64
	ConsultantName string
	AppointmentDate string
	Period string
	Status int
	InterpretingState int
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Consultant struct {
	Id int64 `xorm:"pk autoincr"`
	Name string
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ApplyRecord struct {
	Id int64 `xorm:"pk autoincr"`
	OrderId int64
	CustomerId int64
	CustomerName string
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Dateable struct {
	Name string
	AppointmentPeriodList []*AppointmentPeriod
}

type AppointmentPeriod struct {
	Name string
	IsThereAnAppointment bool
	AppointmentRecord *AppointmentRecord
}

func GetMonth(m string) int{
	switch m {
	case "January":
		return 1
	case "February":
		return 2
	case "March":
		return 3
	case "April":
		return 4
	case "May":
		return 5
	case "June":
		return 6
	case "July":
		return 7
	case "August":
		return 8
	case "September":
		return 9
	case "October":
		return 10
	case "November":
		return 11
	case "December":
		return 12
	}
	return 0
}

func ZellerWeek(year, month, day int) string {

	var weekday = [7]string{"周日", "周一", "周二", "周三", "周四", "周五", "周六"}

	var y, m, c int
	if month >= 3 {
		m = month
		y = year % 100
		c = year / 100
	} else {
		m = month + 12
		y = (year - 1) % 100
		c = (year - 1) / 100
	}

	week := y + (y / 4) + (c / 4) - 2*c + ((26 * (m + 1)) / 10) + day - 1
	if week < 0 {
		week = 7 - (-week)%7
	} else {
		week = week % 7
	}
	which_week := week
	return weekday[which_week]
}

func (c * Consultant)QueryConsultantBookingTime(cIt int64) (interface{}, error){

	var dateableList []*Dateable

	now := time.Now()
	var count int = 0
	for {
		if len(dateableList) == 14{
			break
		}

		cTime := now.AddDate(0,0,count)

		y := cTime.Year()
		m := cTime.Month().String()
		gm := GetMonth(m)
		d := cTime.Day()

		today := ZellerWeek(y, gm, d)

		if today == "周日" || today == "周六"{
			count += 1
			continue
		}

		var db Dateable
		db.Name = cTime.Format("2006-01-02")
		dateableList = append(dateableList, &db)

		count += 1
	}

	for _, dlv := range dateableList{

		var appointmentPeriodList []*AppointmentPeriod

		list := []string{"09:10 - 09:40", "09:50 - 10:20", "10:30 - 11:00", "11:10 - 11:40", "13:40 - 14:10", "14:20 - 14:50", "15:10 - 15:40", "16:10 - 16:40", "16:50 - 17:20", "17:20 - 17:50"}
		for _, lv := range list{
			var ap  = AppointmentPeriod{
				Name:lv,
			}
			appointmentPeriodList = append(appointmentPeriodList, &ap)
		}
		dlv.AppointmentPeriodList = appointmentPeriodList

		for _, aplv := range dlv.AppointmentPeriodList{
			var bt BookingTime
			x.Where("consultant_id = ?", cIt).And("appointment_date = ?", dlv.Name).And("period = ?", aplv.Name).Get(&bt)
			if bt.Id != 0{
				aplv.IsThereAnAppointment = true
				if bt.Reserved == 2{
					aplv.AppointmentRecord = new(AppointmentRecord)
					x.Where("consultant_id = ? ", cIt).And("appointment_date = ?", dlv.Name).And("period = ?", aplv.Name).Get(aplv.AppointmentRecord)
				}
			}
		}
	}

	return dateableList, nil
}

func (c * Consultant)QueryConsultantBookingTimeAsync(cIt int64) (interface{}, error){

	var dateableList []*Dateable

	now := time.Now()
	var count int = 0
	for {
		if len(dateableList) == 14{
			break
		}

		cTime := now.AddDate(0,0,count)

		y := cTime.Year()
		m := cTime.Month().String()
		gm := GetMonth(m)
		d := cTime.Day()

		today := ZellerWeek(y, gm, d)

		if today == "周日" || today == "周六"{
			count += 1
			continue
		}

		var db Dateable
		db.Name = cTime.Format("2006-01-02")
		dateableList = append(dateableList, &db)

		count += 1
	}

	var wg sync.WaitGroup
	wg.Add(7)

	for i := 0; i < 7; i++ {
		var actuil int = i
		go func() {
			defer func() {
				// 捕获异常 防止waitGroup阻塞
				if err := recover(); err != nil {
					wg.Done()
				}
			}()

			for _, dlv := range dateableList[actuil*2:(actuil+1)*2] {

				var appointmentPeriodList []*AppointmentPeriod

				list := []string{"09:10 - 09:40", "09:50 - 10:20", "10:30 - 11:00", "11:10 - 11:40", "13:40 - 14:10", "14:20 - 14:50", "15:10 - 15:40", "16:10 - 16:40", "16:50 - 17:20", "17:20 - 17:50"}
				for _, lv := range list {
					var ap = AppointmentPeriod{
						Name: lv,
					}
					appointmentPeriodList = append(appointmentPeriodList, &ap)
				}
				dlv.AppointmentPeriodList = appointmentPeriodList

				for _, aplv := range dlv.AppointmentPeriodList {
					var bt BookingTime
					x.Where("consultant_id = ?", cIt).And("appointment_date = ?", dlv.Name).And("period = ?", aplv.Name).Get(&bt)
					if bt.Id != 0 {
						aplv.IsThereAnAppointment = true
						if bt.Reserved == 2 {
							aplv.AppointmentRecord = new(AppointmentRecord)
							x.Where("consultant_id = ? ", cIt).And("appointment_date = ?", dlv.Name).And("period = ?", aplv.Name).Get(aplv.AppointmentRecord)
						}
					}
				}
			}

			wg.Done()
		}()
	}

	wg.Wait()
	
	return dateableList, nil
}

func (c * Consultant)InsertConsultantBookingTime(dList []*Dateable, cId int64)(map[string]interface{}, error){

	w := new(utils.Worker)

	for _, d := range dList{
		for _ ,ap := range d.AppointmentPeriodList{
			if ap.IsThereAnAppointment == true{
				var bt BookingTime
				x.Where("consultant_id = ?", cId).And("appointment_date = ?", d.Name).And("period = ?", ap.Name).Get(&bt)
				if bt.Id == 0{
					bt.Id = w.GetId()
					bt.ConsultantId = cId
					bt.AppointmentDate = d.Name
					bt.Period = ap.Name
					bt.Reserved = 1
					bt.CreatedAt = time.Now()
					bt.UpdatedAt = time.Now()
					x.Insert(&bt)
				}
			}else {
				var bt BookingTime
				x.Where("consultant_id = ?", cId).And("appointment_date = ?", d).And("period = ?", ap).Get(&bt)
				if bt.Id != 0{
					x.Id(bt.Id).Delete(&bt)
				}
			}
		}
	}
	return map[string]interface{}{"message": "成功","code":"200"}, nil
}

func (c * Consultant)QueryConsultantTime(cId int64, d string)([]*BookingTime, error){

	var btList []*BookingTime
	x.Where("consultant_id = ? ", cId).And("reserved = ?", 1).And("appointment_date = ?", d).Find(&btList)

	return btList, nil

}

func (c * Consultant)CancelReservation(arId int64, cId int64, ad string, p string)(map[string]interface{}, error){

	ar := new(AppointmentRecord)
	ar.Status = 2
	x.Id(arId).Update(ar)

	bt := new(BookingTime)
	bt.Reserved = 1
	x.Where("consultant_id = ? ", cId).And("appointment_date = ?", ad).And("period = ?", p).Update(bt)

	return map[string]interface{}{"message": "成功","code":"200"}, nil
}

var lock sync.Mutex

func (c * Consultant)InsertRecord(cId int64, cName string, oId int64, d string, p string)(map[string]interface{}, error){

	lock.Lock()

	lbt := new(BookingTime)
	x.Where("consultant_id = ? ", cId).And("appointment_date = ?", d).And("period = ?", p).Get(lbt)
	if lbt.Reserved == 2{

		lock.Unlock()
		
		return map[string]interface{}{"message": "该时间段已被预约","code":"400"}, nil
	}

	w := new(utils.Worker)

	var ar = AppointmentRecord{
		Id: 			   w.GetId(),
		OrderId:           oId,
		ConsultantId:      cId,
		ConsultantName:    cName,
		AppointmentDate:   d,
		Period:            p,
		Status:            1,
		InterpretingState: 1,
		CreatedAt:         time.Now(),
		UpdatedAt:         time.Now(),
	}
	x.Insert(&ar)

	bt := new(BookingTime)
	bt.Reserved = 2
	x.Where("consultant_id = ? ", cId).And("appointment_date = ?", d).And("period = ?", p).Update(bt)

	lock.Unlock()

	return map[string]interface{}{"message": "成功","code":"200"}, nil
}

func (c * Consultant)Evaluate(result string, cId int64, cName string)(map[string]interface{}, error){

	w := new(utils.Worker)

	if result == "2" || result == "3"{
		var ar = ApplyRecord{
			Id:           w.GetId(),
			CustomerId:   cId,
			CustomerName: cName,
			CreatedAt:    time.Now(),
			UpdatedAt:    time.Now(),
		}
		x.Insert(&ar)
	}

	return map[string]interface{}{"message": "成功","code":"200"}, nil
}